//
// Created by root on 5/14/17.
//

#include <stdio.h>
#include "../base/cmocka_test.h"
#include "runner_lex.h"

static void test_replace_string_with_number() {
    String string = replace_string_with_number("<real>-<ureal>i", '<', '>', '\\');
    assert_string_equal(string, "<1>-<2>i");
    string = replace_string_with_number("<real>\\<-\\><ureal>i", '<', '>', '\\');
    assert_string_equal(string, "<1><-><2>i");
    string = replace_string_with_number("<real>\\a-\\b<ureal>i", '<', '>', '\\');
    assert_string_equal(string, "<1>\\a-\\b<2>i");
}

static void test_match_regex() {
    Rule *t;
    hashmap_get(rules, "bool", (void**)(&t));
    assert_true(match_regex(t->regex, "#t"));
    assert_true(match_regex(t->regex, "#f"));

    hashmap_get(rules, "char", (void**)(&t));
    assert_true(match_regex(t->regex, "#\\a"));
    assert_true(match_regex(t->regex, "#\\#"));
    //assert_true(match_regex("#\\\\[[:graph:]]", "#\\ "));

    hashmap_get(rules, "str", (void**)(&t));
    assert_true(match_regex(t->regex, "\"abc\""));
    assert_true(match_regex(t->regex, "\" \\ \" \""));
    assert_true(match_regex(t->regex, "\" \" \\ \""));
    assert_true(match_regex(t->regex, "\" abc \\\\ \\\" \""));

    hashmap_get(rules, "suffix", (void**)(&t));
    assert_true(match_regex(t->regex, "e123"));
    assert_true(match_regex(t->regex, "e+123"));
    assert_true(match_regex(t->regex, "e-123"));

    hashmap_get(rules, "sign", (void**)(&t));
    assert_true(match_regex(t->regex, ""));
    assert_true(match_regex(t->regex, "+"));
    assert_true(match_regex(t->regex, "-"));

    hashmap_get(rules, "digit", (void**)(&t));
    assert_true(match_regex(t->regex, "5"));

    hashmap_get(rules, "initial", (void**)(&t));
    assert_true(match_regex(t->regex, "a"));
    assert_true(match_regex(t->regex, "Z"));
    assert_true(match_regex(t->regex, "/"));

    hashmap_get(rules, "subsequent", (void**)(&t));
    assert_true(match_regex(t->regex, "a"));
    assert_true(match_regex(t->regex, "Z"));
    assert_true(match_regex(t->regex, "5"));
    assert_true(match_regex(t->regex, "/"));
    assert_true(match_regex(t->regex, "-"));

    hashmap_get(rules, "peculiar", (void**)(&t));
    assert_true(match_regex(t->regex, "+"));
    assert_true(match_regex(t->regex, "-"));
    assert_true(match_regex(t->regex, "..."));

    hashmap_get(rules, "letter", (void**)(&t));
    assert_true(match_regex(t->regex, "a"));
    assert_true(match_regex(t->regex, "Z"));
}

static void test_match_regex_groups() {
    String *strings = match_regex_groups("([0-9]+.[0-9]*e[0-9]+)-([0-9]*)/([0-9]*)i", 4, "3.1e2-5/6i");
    assert_string_equal(*strings, "3.1e2-5/6i");
    assert_string_equal(*(strings + 1), "3.1e2");
    assert_string_equal(*(strings + 2), "5");
    assert_string_equal(*(strings + 3), "6");
    assert_null(*(strings + 4));

    strings = match_regex_groups("\"([^\"\\\\]*(\\\\.[^\"\\\\]*)*)\"", 1, "\" abc \\\\ \\\" \"");
    assert_string_equal(*strings, "\" abc \\\\ \\\" \"");
}

static void test_lex_to_function_boolean() {
    assert_string_equal(lex_to_function("boolean", "#t"), "(lex \"Boolean\" \"#t\")");
    assert_string_equal(lex_to_function("boolean", "#f"), "(lex \"Boolean\" \"#f\")");
}

static void test_lex_to_function_character() {
    assert_string_equal(lex_to_function("character", "#\\a"), "(lex \"Character\" \"#\\a\")");
    assert_string_equal(lex_to_function("character", "#\\space"), "(lex \"Character\" \"#\\space\")");
    assert_string_equal(lex_to_function("character", "#\\newline"), "(lex \"Character\" \"#\\newline\")");
}

static void test_lex_to_function_string() {
    assert_string_equal(lex_to_function("string", "\" abc \\\\ \\\" \""), "(lex \"String\" \" abc \\\\ \\\" \")");
    assert_string_equal(lex_to_function("string", "\"\\\\\""), "(lex \"String\" \"\\\\\")");
    assert_string_equal(lex_to_function("string", "\"\\\"\""), "(lex \"String\" \"\\\"\")");
}

static void test_lex_to_function_symbol() {
    assert_string_equal(lex_to_function("symbol", "abc"), "(lex \"Symbol\" \"abc\")");
    assert_string_equal(lex_to_function("symbol", "+"), "(lex \"Symbol\" \"+\")");
    assert_string_equal(lex_to_function("symbol", "-"), "(lex \"Symbol\" \"-\")");
    assert_string_equal(lex_to_function("symbol", "..."), "(lex \"Symbol\" \"...\")");
}

static void test_lex_to_function_integer() {
    assert_string_equal(lex_to_function("integer", "123"), "(lex \"Integer\" \"123\")");
}

static void test_lex_to_function_fraction() {
    assert_string_equal(lex_to_function("fraction", "1/2"), "(make-fraction (lex \"Integer\" \"1\") (lex \"Integer\" \"2\"))");
}

static void test_lex_to_function_decimal() {
    assert_string_equal(lex_to_function("decimal", "0.123"), "(lex \"Decimal\" \"0.123\")");
}

static void test_lex_to_function_complex() {
    assert_string_equal(lex_to_function("complex", "1/2+5/6i"), "(make-complex (make-fraction (lex \"Integer\" \"1\") (lex \"Integer\" \"2\")) (make-fraction (lex \"Integer\" \"5\") (lex \"Integer\" \"6\")))");
}

static void test_expand_lex() {
    assert_string_equal(expand_lex("1"), "(lex \"Integer\" \"1\")");
    assert_string_equal(expand_lex("abc"), "(lex \"Symbol\" \"abc\")");
    assert_string_equal(expand_lex("\"abc\""), "(lex \"String\" \"abc\")");
    assert_string_equal(expand_lex("#t"), "(lex \"Boolean\" \"#t\")");
    assert_string_equal(expand_lex("#\\a"), "(lex \"Character\" \"#\\a\")");
    assert_string_equal(expand_lex("5/6"), "(make-fraction (lex \"Integer\" \"5\") (lex \"Integer\" \"6\"))");
    assert_string_equal(expand_lex("3.14"), "(lex \"Decimal\" \"3.14\")");
    assert_string_equal(expand_lex("0.314e10"), "(lex \"Decimal\" \"0.314e10\")");
    assert_string_equal(expand_lex("3.14+4/5i"), "(make-complex (lex \"Decimal\" \"3.14\") (make-fraction (lex \"Integer\" \"4\") (lex \"Integer\" \"5\")))");
    assert_string_equal(expand_lex("+i"), "(make-complex (lex \"Integer\" \"0\") (lex \"Integer\" \"1\"))");
    assert_string_equal(expand_lex("-i"), "(make-complex (lex \"Integer\" \"0\") (lex \"Integer\" \"-1\"))");
    assert_string_equal(expand_lex("+2i"), "(make-complex (lex \"Integer\" \"0\") (lex \"Integer\" \"2\"))");
    assert_string_equal(expand_lex("-2i"), "(make-complex (lex \"Integer\" \"0\") (- (lex \"Integer\" \"2\")))");
    assert_string_equal(expand_lex("1+i"), "(make-complex (lex \"Integer\" \"1\") (lex \"Integer\" \"1\"))");
    assert_string_equal(expand_lex("1-i"), "(make-complex (lex \"Integer\" \"1\") (lex \"Integer\" \"-1\"))");
    assert_string_equal(expand_lex("3+2i"), "(make-complex (lex \"Integer\" \"3\") (lex \"Integer\" \"2\"))");
    assert_string_equal(expand_lex("-4"), "(lex \"Integer\" \"-4\")");
    assert_string_equal(expand_lex("-4/3+4.5i"), "(make-complex (make-fraction (lex \"Integer\" \"-4\") (lex \"Integer\" \"3\")) (lex \"Decimal\" \"4.5\"))");
}

int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            cmocka_unit_test(test_replace_string_with_number),
            cmocka_unit_test(test_match_regex),
            cmocka_unit_test(test_match_regex_groups),
            cmocka_unit_test(test_lex_to_function_boolean),
            cmocka_unit_test(test_lex_to_function_character),
            cmocka_unit_test(test_lex_to_function_string),
            cmocka_unit_test(test_lex_to_function_symbol),
            cmocka_unit_test(test_lex_to_function_integer),
            cmocka_unit_test(test_lex_to_function_fraction),
            cmocka_unit_test(test_lex_to_function_decimal),
            cmocka_unit_test(test_lex_to_function_complex),
            cmocka_unit_test(test_expand_lex)
    };
    return cmocka_run_group_tests(tests, setup_lex, teardown_lex);
}
